package com.billow.net
{
	import com.billow.encode.AES;
	import com.billow.events.UDPSocketEvent;
	
	import flash.events.DatagramSocketDataEvent;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.DatagramSocket;
	import flash.utils.ByteArray;
	
	[Event(name="receive", type="com.billow.events.UDPSocketEvent")]
	[Event(name="ioError", type="com.billow.events.UDPSocketEvent")]
	[Event(name="rangeError", type="com.billow.events.UDPSocketEvent")]
	[Event(name="failed", type="com.billow.events.UDPSocketEvent")]
	[Event(name="succeed", type="com.billow.events.UDPSocketEvent")]
	
	public class UDPSocket extends EventDispatcher
	{
		private var _datagramSocket:DatagramSocket;
		private var _key:String;
		
		public function UDPSocket(key:String=null)
		{
			_key = key;
		}
		
		
		
		
		////////////////////////////////////////////////////////////////////
		//
		//  get
		//
		///////////////////////////////////////////////////////////////////
		
		private var _cmd:String;
		private var _data:ByteArray;
		private var _remoteAddress:String;
		private var _remotePort:int;
		
		/** 远程设备的 IP 地址 */
		public function get remoteAddress():String {return _remoteAddress;}
		
		/** 远程设备的端口 */
		public function get remotePort():int {return _remotePort;}
		
		/** 参数 */
		public function get data():ByteArray {return _data;}
		
		/** 命令 */
		public function get cmd():String {return _cmd;}
		
		/** 表示此 Socket 对象当前是否绑定到本地地址和端口 */
		public function get bound():Boolean {return _datagramSocket.bound;}
		
		
		////////////////////////////////////////////////////////////////////
		//
		//  Public
		//
		///////////////////////////////////////////////////////////////////
		
		/**
		 * 开启服务器 
		 * @param localPort
		 * @param localAddress
		 * 
		 */		
		public function bind(localPort:int = 0, localAddress:String = "0.0.0.0"):void
		{
			try{
				_datagramSocket = new DatagramSocket();
				if(_datagramSocket.bound) 
				{
					_datagramSocket.close();
					_datagramSocket = new DatagramSocket();
				}
				
				_datagramSocket.bind(localPort, localAddress);
				_datagramSocket.addEventListener(DatagramSocketDataEvent.DATA, dataReceived);
				_datagramSocket.addEventListener(IOErrorEvent.IO_ERROR ,ioerror);
				_datagramSocket.receive();
				
				dispatchEvent(new UDPSocketEvent(UDPSocketEvent.SUCCEED));
			}catch(e:Error){
				dispatchEvent(new UDPSocketEvent(UDPSocketEvent.FAILED));
			}
		}
		
		
		/**
		 * 关闭服务 
		 * 
		 */		
		public function close():void
		{
			if(_datagramSocket!=null)
			{
				if(_datagramSocket.bound)_datagramSocket.close();
				_datagramSocket.removeEventListener(DatagramSocketDataEvent.DATA, dataReceived);
				_datagramSocket.removeEventListener(IOErrorEvent.IO_ERROR ,ioerror);
				_datagramSocket = null;
			}
		}
		
		
		
		/*public function connect(remoteAddress:String, remotePort:int):void
		{
			_datagramSocket.connect(remoteAddress ,remotePort);
		}*/
		
		
		/**
		 * 发送数据 
		 * @param cmd
		 * @param value
		 * @param address
		 * @param port
		 * 
		 */							
		public function send(cmd:String ,value:ByteArray=null ,address:String = null, port:int = 0):void
		{
			var bytes:ByteArray = new ByteArray();
			bytes.writeUTF(_key==null?cmd:AES.encrypt(cmd ,_key ,AES.BIT_KEY_192));
			bytes.writeInt(value==null?0:value.length);
			if(value!=null)bytes.writeBytes(value ,0 ,value.length);
			
			if(bytes.length<=1 || bytes.length>=65535-50)
			{
				dispatchEvent(new UDPSocketEvent(UDPSocketEvent.RANGE_ERROR));
			}else{
				_datagramSocket.send(bytes ,0 ,bytes.length ,address ,port);
			}
			
			bytes.clear();
			bytes = null;
		}
		
		
		
		////////////////////////////////////////////////////////////////////
		//
		//  Event
		//
		///////////////////////////////////////////////////////////////////
		
		/** 错误信息 */
		private function ioerror(event:IOErrorEvent):void
		{
			dispatchEvent(new UDPSocketEvent(UDPSocketEvent.IO_ERROR));
		}
		
		/** 读取数据 */
		private function dataReceived(event:DatagramSocketDataEvent):void
		{
			try{
				_cmd = _key==null?event.data.readUTF():AES.decrypt(event.data.readUTF() ,_key ,AES.BIT_KEY_192);
				
				if(_data!=null)
				{
					_data.clear();
					_data = null;
				}
				
				if(event.data.readInt()>0)
				{
					_data = new ByteArray();
					event.data.readBytes(_data ,0 ,event.data.bytesAvailable);
				}
				
				_remoteAddress = event.srcAddress;
				_remotePort = event.srcPort;
				dispatchEvent(new UDPSocketEvent(UDPSocketEvent.RECEIVE ,this));
			}catch(e:Error){
				dispatchEvent(new UDPSocketEvent(UDPSocketEvent.IO_ERROR));
			}
		}
	}
}